
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stddef.h>
#include <ICC/clock_countor.h>
#include <ICC/etu_timer.h>
#include <ICC/error_code.h>
#include <ICC/base.h>
#include <ICC/slot.h>
#include "BSP_SmartCard.h"
#include "BSP_Uart_2.h"
#include "IO.h"

#define TRANSFER_OUT	0
#define TRANSFER_IN	1

/*
	USART Parity-Select-Bit address Caculate. See DataSheet V10.1 section2.3.2
*/
/* Private macro -------------------------------------------------------------*/

/*Private function-----------------------------------------------------------*/
static void USART_SetDivider(uint32_t USARTx, uint32_t F, uint32_t D );
#include "FreeRTOS.h"
#include "stream_buffer.h"
#include "Debug.h"

static StreamBufferHandle_t sc_uart_stream_buffer = NULL;

/* Private variables ---------------------------------------------------------*/


/* Global variables definition and initialization ----------------------------*/


hardware_module_t SmartCardUsarts[1] = {
	[0] = {
	    USART0, //usart
		AFIO_INIT(GPIOA, GPIO_PIN_2, GPIO_AF_0),
	    DIRECT_BYTE,//byte_direction
	    TRANSFER_IN,	//transfer_direction
	    USART_FLAG_TC,	//send_complete_flag
	    8				//uint32_t frequency_fraction
	},
#if 0
	[1] = {
	    USART1, //usart
	    USART_Parity_Select_Bit_Addr(USART1),
	    DIRECT_BYTE,//byte_direction
	    TRANSFER_IN,	//transfer_direction
	    USART_FLAG_TC,	//send_complete_flag
	    8				//uint32_t frequency_fraction
	},
#endif 
};
/*!
    \brief      this function handles USART0 exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void USART0_IRQHandler1(void)
{
    if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)){
		uint16_t data = usart_data_receive(USART0);
		if(sc_uart_stream_buffer){
			BaseType_t xHigherPriorityTaskWoken = pdFALSE;
			int len = xStreamBufferSendFromISR(sc_uart_stream_buffer, &data, sizeof(data), &xHigherPriorityTaskWoken);
			if(len != sizeof(data)){
				LOG_E("rx (%04X)fail!", data);
			}
			portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
		}
    }       
    if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_TBE)){
    }
}

static void SC_RxCallback(uint16_t data){
	if(sc_uart_stream_buffer){
		BaseType_t xHigherPriorityTaskWoken = pdFALSE;
		int len = xStreamBufferSendFromISR(sc_uart_stream_buffer, &data, sizeof(data), &xHigherPriorityTaskWoken);
		if(len != sizeof(data)){
			LOG_E("rx (%04X)fail!", data);
		}
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
	}
}


static void HardwareModule_RCC_Enable(void)
{
	rcu_periph_clock_enable(RCU_USART0);
}

#if 0
static void SC_USART_Init(uint32_t com)
{
    /* USART configure */
    usart_deinit(com);

	usart_synchronous_clock_config(com, USART_CLEN_EN, USART_CPH_1CK, USART_CPL_LOW);
	usart_clock_enable(com);
	
    usart_guard_time_config(com, 1);
	usart_prescaler_config(com, 4);
	
    usart_baudrate_set(com, 10753);
    usart_word_length_set(com, USART_WL_9BIT);
    usart_stop_bit_set(com, USART_STB_1_5BIT);
    usart_parity_config(com, USART_PM_EVEN);
    usart_hardware_flow_rts_config(com, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(com, USART_CTS_DISABLE);
    usart_receive_config(com, USART_RECEIVE_ENABLE);
    usart_transmit_config(com, USART_TRANSMIT_ENABLE);

    usart_enable(com);	
	usart_smartcard_mode_enable(com);
	usart_smartcard_mode_nack_disable(com);
}
#endif 
static void SC_USART_Init(uint32_t periph)
{
    /* disable the peripheral */
    usart_disable(periph);
    /* baud rate configure */
    usart_baudrate_set(periph, 10752);
    usart_parity_config(periph, USART_PM_EVEN);
    usart_word_length_set(periph, USART_WL_9BIT);
    usart_stop_bit_set(periph, USART_STB_1_5BIT);
    usart_transmit_config(periph, USART_TRANSMIT_ENABLE);
    usart_receive_config(periph, USART_RECEIVE_ENABLE);
    usart_sample_bit_config(periph, USART_OSB_3BIT);
    usart_prescaler_config(periph, 4);
    usart_guard_time_config(periph, 1);
    usart_smartcard_mode_nack_disable(periph);
    usart_receiver_timeout_disable(periph);
    usart_block_length_config(periph, 0);
    usart_smartcard_autoretry_config(periph, 0);
    usart_synchronous_clock_config(periph, USART_CLEN_EN, USART_CPH_1CK, USART_CPL_LOW);
    usart_clock_enable(periph);
    /* enable SMARTCARD */
    usart_smartcard_mode_enable(periph);

}


static void sc_io_init(void){
#if 0
    /* connect port to USARTx_Clk */
    gpio_af_set(GPIOA, GPIO_AF_0, GPIO_PIN_2);
    /* configure USART Tx as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_2);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_166MHZ, GPIO_PIN_2);

    /* connect port to USARTx_Tx */
    gpio_af_set(GPIOA, GPIO_AF_0, GPIO_PIN_0);
    /* configure USART Tx as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_166MHZ, GPIO_PIN_0);
#endif 
}

void HardwareModule_Reset(hardware_module_t *hw)
{
	hw->transfer_direction = TRANSFER_OUT;
	usart_interrupt_disable(hw->usart, USART_INT_RBNE);
	usart_data_receive(hw->usart);
	if(sc_uart_stream_buffer != NULL){
		xStreamBufferReset(sc_uart_stream_buffer);
	}
}


void HardwareModule_Init(void)
{
	uint8_t i;
	if(sc_uart_stream_buffer == NULL){
		sc_uart_stream_buffer = xStreamBufferCreate(256, 1);
	}
    /* enable peripheral clock  */
	rcu_periph_clock_enable(RCU_USART0);
    rcu_periph_clock_enable(RCU_GPIOA);
	sc_io_init();
	
	BSP_Uart_SetRxCallback(0, SC_RxCallback);
    /* Enable USART clock */
//	    HardwareModule_RCC_Enable();
	SC_USART_Init(USART0);
    /* USART interrupt configuration */
    nvic_irq_enable(USART0_IRQn, 12, 0);
    /* enable USART0 receive interrupt */
    usart_interrupt_disable(USART0, USART_INT_RBNE);
	usart_enable(USART0);
}

static void USART_SetDivider(uint32_t USARTx, uint32_t F, uint32_t D)
{
    uint32_t remainder;
    uint32_t integerdivider;
    uint32_t fractionaldivider;

    /* Integer part computing in case Oversampling mode is 16 Samples */
    integerdivider = F / D;
    //Fraction = remainder /D = DIV_Fraction / 16 => DIV_Fraction = remainder *16/D
    remainder = F % D;
//	    fractionaldivider = (remainder * (16 / 2)) / D;
	fractionaldivider = (remainder * 16) / D;
	usart_disable(USARTx);
    USART_BAUD(USARTx) = ((USART_BAUD_FRADIV | USART_BAUD_INTDIV) & (integerdivider << 4 | (fractionaldivider & 0x0F)));
	usart_enable(USARTx);
}


void HardwareModule_ClockEnable(hardware_module_t *hw)
{
	usart_clock_enable(hw->usart);
	usart_enable(hw->usart);
}

void HardwareModule_ClockDisable(hardware_module_t *hw)
{
	usart_clock_disable(hw->usart);
	usart_enable(hw->usart);
}

void HardwareModule_SetStopbits(hardware_module_t *hw, uint8_t stopbits)
{
    uint16_t stopbits_mark = stopbits == 1 ? USART_STB_0_5BIT : USART_STB_1_5BIT;
	usart_stop_bit_set(hw->usart, stopbits_mark);
	usart_enable(hw->usart);
}

void HardwareModule_NAKEnable(hardware_module_t *hw)
{
	usart_smartcard_mode_nack_enable(hw->usart);
	usart_enable(hw->usart);
}

void HardwareModule_NAKDisable(hardware_module_t *hw)
{
	usart_smartcard_mode_nack_disable(hw->usart);
	usart_enable(hw->usart);
}
extern uint32_t etu_to_clock(uint32_t etu, uint8_t FiDi);
void HardwareModule_SoftwareNak(uint8_t FiDi)
{
}


static inline void HardwareModule_SetParityOdd(hardware_module_t *hw)
{
}

static inline void HardwareModule_SetParityEven(hardware_module_t *hw)
{
}

void HardwareModule_SetByteDirection(hardware_module_t *hw, uint8_t dir)
{
    if(dir != DIRECT_BYTE)
    {
        HardwareModule_SetParityOdd(hw);
    }
    else
    {
        HardwareModule_SetParityEven(hw);
    }

    hw->byte_direction = dir;
}

uint8_t HardwareModule_GetByteDirection(hardware_module_t *hw)
{
    return hw->byte_direction;
}

void HardwareModule_SetETU(hardware_module_t *hw, uint8_t FiDi)
{
    uint32_t F;
    uint32_t D;
    uint32_t frequency_fraction = hw->frequency_fraction;

    F = convert_fi_code_to_value(FiDi >> 4);
    D = convert_di_code_to_value(FiDi & 0x0F);
    F = F * frequency_fraction / 16;
    USART_SetDivider(hw->usart, F, D);
}

static uint32_t Usart_GetFrequency(uint32_t usart)
{
	if(usart == USART2)
	{
		return rcu_clock_freq_get(CK_APB2);
	}
	return rcu_clock_freq_get(CK_APB1);
}

void HardwareModule_SetFrequency(hardware_module_t *hw, uint32_t frequency)
{
    uint32_t usart = hw->usart;
    uint32_t usart_freq = Usart_GetFrequency(usart);
    uint32_t div = usart_freq / frequency;
    
    hw->frequency_fraction = div;
	usart_prescaler_config(usart, div / 2);
	usart_enable(hw->usart);
}

void HardwareModule_SetGuardTime(hardware_module_t *hw, uint8_t guard_time)
{
	usart_guard_time_config(hw->usart, guard_time);
	usart_enable(hw->usart);
}

void HardwareModule_SetCharDuration(hardware_module_t *hw, uint8_t char_duration)
{
    if(char_duration == 11)
    {
        hw->send_complete_flag = USART_FLAG_TBE;
    }
    else
    {
        hw->send_complete_flag = USART_FLAG_TC;
    }
}


#define direct_send_byte(hw, byte) 	usart_data_transmit((hw)->usart, byte)
#define reverse_send_byte(hw, byte) usart_data_transmit((hw)->usart, reverse_byte(~(byte)))
#define is_send_complete(sr, complete_flag) ((sr) & (complete_flag))

static uint16_t flush_receive_buffer(hardware_module_t* hw){
	return usart_data_receive(hw->usart);
}

static void clear_send_error(hardware_module_t *hw){
	uint32_t usart = hw->usart;
	usart_flag_get(usart, USART_FLAG_FERR);
	usart_data_receive(usart);
}

uint8_t HardwareModule_CheckNAK(hardware_module_t *hw)
{
    uint32_t i;
    uint8_t err = NO_ERR;
	uint32_t usart = hw->usart;
	
    for(i = 0; i < 30; i++)    {
		if(usart_flag_get(usart, USART_FLAG_FERR)){
			usart_data_receive(usart);
			err = ERR_SEND;
			break;
		}
    }

    return err;
}


uint8_t HardwareModule_SendByte(hardware_module_t *hw, uint8_t byte)
{
    uint8_t err = NO_ERR;
	uint32_t usart = hw->usart;
	uint32_t clk = 1000 * 10;
	
//		usart_receive_config(usart, USART_RECEIVE_DISABLE);
//	    usart_command_enable(usart, USART_CMD_RXFCMD);
//	    usart_transmit_config(usart, USART_TRANSMIT_ENABLE);
	
	if(hw->transfer_direction != TRANSFER_OUT){
	    hw->transfer_direction = TRANSFER_OUT;
		clear_send_error(hw);
		usart_interrupt_disable(hw->usart, USART_INT_RBNE);
		xStreamBufferReset(sc_uart_stream_buffer);
	}
	uint32_t c1 = ETUTimer_GetCountor();
	uint32_t c2;
	while(RESET == usart_flag_get(usart, USART_FLAG_TBE)){
		c2 = ETUTimer_GetCountor();
		if((c2-c1) > clk) {
			break;
		}
	}
	usart_data_transmit(usart, byte);
	c1 = ETUTimer_GetCountor();
	while(RESET == usart_flag_get(usart, USART_FLAG_TC)){
		c2 = ETUTimer_GetCountor();
		if((c2-c1) > clk) {
			break;
		}
	}
//	    usart_transmit_config(usart, USART_RECEIVE_ENABLE);
    return err;
}


uint16_t HardwareModule_Flush(hardware_module_t *hw)
{
    return flush_receive_buffer(hw);
}

static uint16_t reverse_receive_byte(hardware_module_t *hw)
{
    uint16_t data = USART_RDATA(hw->usart);
    uint16_t parity_bit;

    data = ~data;
    parity_bit = data & 0x0100;

    return (uint16_t)reverse_byte((uint8_t)data) | parity_bit;
}


#define is_parity_error(sr) ((sr) & USART_FLAG_PERR)
#define is_receive_compelet(sr) ((sr) & USART_FLAG_RBNE)
#define get_receive_error_mark(hw) ((hw)->error_mark & (~USART_FLAG_FERR))


static uint16_t receive_data(hardware_module_t *hw){
	return ((hw)->byte_direction != DIRECT_BYTE) 
		?  reverse_receive_byte(hw)
		: USART_RDATA(hw->usart);
}

uint8_t HardwareModule_ReceiveByte(hardware_module_t *hw, uint16_t *byte, uint32_t clk)
{

	if(sc_uart_stream_buffer == NULL){
		return ERR_RECEIVE;
	}
	
    if(hw->transfer_direction == TRANSFER_OUT){
        hw->transfer_direction = TRANSFER_IN;
        flush_receive_buffer(hw);
		xStreamBufferReset(sc_uart_stream_buffer);
		usart_interrupt_enable(hw->usart, USART_INT_RBNE);
    }
	
	if(SET == usart_flag_get(hw->usart, USART_FLAG_FERR)){
		receive_data(hw);
	}
	//按4.5MHz计算时间
	uint32_t wtime = clk / (4 * 1000) + 1;
	int ret = xStreamBufferReceive(sc_uart_stream_buffer, byte, sizeof(*byte), wtime);
	if(ret != sizeof(*byte)){
		return ERR_TIMEOUT;
	}

    return NO_ERR;
}


#if 0

void test_HardwareModule(void)
{
	static uint16_t rx = 0;
	static uint8_t tx = 0xC0;
    volatile uint32_t i;
	
    HardwareModule_Init();
    HardwareModule_SetGuardTime(&SmartCardUsarts[0], 0);

    while(1)
    {
        //
        HardwareModule_SendByte(&SmartCardUsarts[0], tx);
        HardwareModule_SendByte(&SmartCardUsarts[0], tx);

        for(i = 0; i < 0xFFFF; i++)
        {}

		HardwareModule_SetGuardTime(&SmartCardUsarts[0], 1);
		HardwareModule_SendByte(&SmartCardUsarts[0], 0x55);
		HardwareModule_SendByte(&SmartCardUsarts[0], 0x55);
		HardwareModule_ReceiveByte(&SmartCardUsarts[0], &rx, 1000);
		for(i = 0; i < 0xFFFF; i++)
		{}
    }
}
#endif

